{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "# TensorFlow による分散型トレーニング"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r6P32iYYV27b"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/distributed_training\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org で表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/distributed_training.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/distributed_training.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/distributed_training.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xHxb-dlhMIzW"
      },
      "source": [
        "## 概要\n",
        "\n",
        "`tf.distribute.Strategy` は、複数の GPU、複数のマシン、または TPU でトレーニングを分散する TensorFlow API です。この API を使用すると、最小限のコード変更により、既存のモデルとトレーニングコードを分散することができます。\n",
        "\n",
        "`tf.distribute.Strategy` は、次の主な目標を念頭に設計されています。\n",
        "\n",
        "- 使いやすく、研究者や ML エンジニアなど、複数のユーザーセグメントをサポートすること。\n",
        "- 調整することなく優れたパフォーマンスを提供できること。\n",
        "- ストラテジーを簡単に切り替えられること。\n",
        "\n",
        "`tf.distribute.Strategy` は、[Keras](https://www.tensorflow.org/guide/keras) などの高レベル API とともに使用でき、カスタムトレーニングループ（と通常、TensorFlow を使用するあらゆる計算）を分散するためにも使用できます。\n",
        "\n",
        "TensorFlow 2.x では、プログラムを Eager モードで、または [`tf.function`](function.ipynb) を使用してグラフ内で実行することができます。`tf.distribute.Strategy` はこれらの実行モードをサポートするのが狙いですが、`tf.function` を使用するのが最適です。Eager モードはデバッグ目的にのみ推奨され、`TPUStrategy` ではサポートされていません。このガイドの大半はトレーニングに関する内容ですが、異なるプラットフォームに評価と予測を分散する上でも、この API を使用することができます。\n",
        "\n",
        "`tf.distribute.Strategy` は、コードをほとんど変更せずに使用することができます。TensorFlow の基盤のコンポーネントをストラテジーを認識するように変更されているからです。これには、変数、レイヤー、モデル、オプティマイザー、メトリック、要約、およびチェックポイントが含まれます。\n",
        "\n",
        "このガイドでは、さまざまなストラテジーと、異なる状況においてそれらのストラテジーをどのように使用するかについて説明します。\n",
        "\n",
        "注意: 概念の理解を深めるには、[こちらの詳しいプレゼンテーション](https://youtu.be/jKV53r9-H14)をご覧ください。独自のトレーニングループを記述する予定の方に、特にお勧めです。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EVOZFbNgXghB"
      },
      "outputs": [],
      "source": [
        "# Import TensorFlow\n",
        "import tensorflow as tf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eQ1QESxxEbCh"
      },
      "source": [
        "## ストラテジーの種類\n",
        "\n",
        "`tf.distribute.Strategy` は、さまざまな軸に沿って多数の使用事例をカバーすることを目的としています。これらの組み合わせの中には、現在サポートされているものもあれば、今後の追加が予定されているものもあります。次に一部の軸を示します。\n",
        "\n",
        "- *同期と非同期トレーニング:* これらは、データの並列処理を使用してトレーニングを分散する 2 つの一般的な方法です。同期トレーニングでは、すべてのワーカーは入力データのさまざまなスライスで同期的にトレーニングし、各ステップで勾配を収集します。一方、非同期トレーニングでは、すべてのワーカーは独立的に入力データでトレーニングし、変数を非同期的に更新します。通常、同期トレーニングは all-reduce を介して、非同期トレーニングはパラメーターサーバーアーキテクチャを介してサポートされています。\n",
        "- *ハードウェアプラットフォーム:* トレーニングを、1台のマシンの複数の GPU またはネットワーク内の複数のマシン（それぞれに 0 個以上の GPU）、さらには Cloud TPU に拡張することができます。\n",
        "\n",
        "こういった使用事例をサポートするために、6 つのストラテジーが用意されています。次のセクションにおいて、現時点の TF 2.2 においてどれがどのシナリオをサポートしているのかについて説明しますが、以下に要約を示します。\n",
        "\n",
        "トレーニング API | MirroredStrategy | TPUStrategy | MultiWorkerMirroredStrategy | CentralStorageStrategy | ParameterServerStrategy\n",
        ":-- | :-- | :-- | :-- | :-- | :--\n",
        "**Keras API** | サポート中 | サポート中 | 実験的サポート | 実験的サポート | 2.3 以降でサポート予定\n",
        "**カスタムトレーニングループ** | サポート中 | サポート中 | 実験的サポート | 実験的サポート | 2.3 以降でサポート予定\n",
        "**Estimator API** | 制限サポート | 未サポート | 制限サポート | 制限サポート | 制限サポート\n",
        "\n",
        "注意: 「[実験的サポート](https://www.tensorflow.org/guide/versions#what_is_not_covered)」とは、API の互換性が保証されていないことを意味します。\n",
        "\n",
        "注意: Estimator のサポートは制限されています。基本的なトレーニングと評価は実験的であり、scaffold といった高度な機能は実装されていません。使用事例がカバーされていない場合は、Keras やカスタムトレーニングループの使用をお勧めします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DoQKKK8dtfg6"
      },
      "source": [
        "### MirroredStrategy\n",
        "\n",
        "`tf.distribute.MirroredStrategy` は、1 台のマシンの複数の GPU での同期分散型トレーニングをサポートしています。GPU デバイス当たり 1 つのレプリカを作成します。モデルの各変数はそのレプリカ全体にミラーリングされます。これらの変数を合わせて形成されるのが、`MirroredVariable` と呼ばれる 1 つの概念的変数です。これらの変数は、同一の更新を適用することで、相互の同期が維持されます。\n",
        "\n",
        "デバイス全体に変数の更新を伝達するには、有効性の高い all-reduce アルゴリズムがし要されます。all-reduce はすべてのデバイスのテンソルを加算して集計し、各デバイスで使用できるようにします。非常に高い効率性と同期のオーバーヘッドを著しく軽減できる、融合アルゴリズムです。デバイス間で利用できる通信の種類に応じて、さまざまな all-reduce アルゴリズムと実装が用意されています。デフォルトでは、all-reduce 実装として NVIDIA NCCL が使用されています。提供されるいくつかのオプションから選ぶこともできれば、独自に作成することもできます。\n",
        "\n",
        "次は、最も単純な `MirroredStrategy` の作成方法です。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9Z4FMAY9ADxK"
      },
      "outputs": [],
      "source": [
        "mirrored_strategy = tf.distribute.MirroredStrategy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wldY4aFCAH4r"
      },
      "source": [
        "これにより、TensorFlow が認識できるすべての GPU を使用する `MirroredStrategy` インスタンスが作成され、クロスデバイス通信として NCCL が使用されるようになります。\n",
        "\n",
        "マシン上の一部の GPU のみを使用する場合は、次のように行うことができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nbGleskCACv_"
      },
      "outputs": [],
      "source": [
        "mirrored_strategy = tf.distribute.MirroredStrategy(devices=[\"/gpu:0\", \"/gpu:1\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8-KDnrJLAhav"
      },
      "source": [
        "クロスデバイス通信をオーバーライドする場合は、`cross_device_ops` 引数に `tf.distribute.CrossDeviceOps` のインスタンスを提供することで実行できます。現在のところ、デフォルトの `tf.distribute.NcclAllReduce` のほかに、`tf.distribute.HierarchicalCopyAllReduce` と `tf.distribute.ReductionToOneDevice` の 2 つのオプションを使用できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6-xIOIpgBItn"
      },
      "outputs": [],
      "source": [
        "mirrored_strategy = tf.distribute.MirroredStrategy(\n",
        "    cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kPEBCMzsGaO5"
      },
      "source": [
        "### TPUStrategy\n",
        "\n",
        "`tf.distribute.experimental.TPUStrategy` は、Tensor Processing Unit（TPU）で TensorFlow トレーニングを実行できるようにします。TPU は、機械学習ワークロードを劇的に高速化するように設計された Google の特殊 ASIC です。Google Colab の [TensorFlow Research Cloud](https://www.tensorflow.org/tfrc) と [Cloud TPU](https://cloud.google.com/tpu) で利用できます。\n",
        "\n",
        "分散型トレーニングアーキテクチャの観点で言えば、`TPUStrategy` は `MirroredStrategy` と同じで、同期分散型トレーニングを実装します。TPU は複数の TPU コアに、効率的な all-reduce の独自の実装とほかの集合演算を提供しており、`TPUStrategy` で使用されています。\n",
        "\n",
        "以下に、`TPUStrategy` をインスタンス化する方法を示します。\n",
        "\n",
        "注意: Colab でこのコードを実行するには、Colab ランタイムとして TPU を選択する必要があります。[TensorFlow TPU ガイド](https://www.tensorflow.org/guide/tpu)を参照してください。\n",
        "\n",
        "```\n",
        "cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(     tpu=tpu_address) tf.config.experimental_connect_to_cluster(cluster_resolver) tf.tpu.experimental.initialize_tpu_system(cluster_resolver) tpu_strategy = tf.distribute.experimental.TPUStrategy(cluster_resolver)\n",
        "```\n",
        "\n",
        "`TPUClusterResolver` インスタンスを使って TPU の場所を特定することができます。Colab では、引数を指定する必要はありません。\n",
        "\n",
        "Cloud TPU でこれを使用する場合は、次の内容に注意してくだい。\n",
        "\n",
        "- `tpu` 引数に、TPU リソースの名前を指定する必要があります。\n",
        "- プログラムの*開始*時点で、tpu システム明示的に初期化する必要があります。これは、TPU が計算に使用される前に必要なことです。tpu システムを初期化すると、TPU メモリも消去されるため、状態を失わないようにするには、この手順を完了しておくことが重要となります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8Xc3gyo0Bejd"
      },
      "source": [
        "### MultiWorkerMirroredStrategy\n",
        "\n",
        "`tf.distribute.experimental.MultiWorkerMirroredStrategy` は、`MirroredStrategy` に非常に似通ったストラテジーです。複数のワーカーにそれぞれ潜在的に複数の GPU を使って同期分散型トレーニングを実装します。`MirroredStrategy` と同様に、すべてのワーカーの各デバイスのモデルにすべての変数のコピーを作成します。\n",
        "\n",
        "マルチワーカー all-reduce 通信方法として [CollectiveOps](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/collective_ops.py) を使用して、変数の同期を維持しています。collective 演算は、TensorFlow グラフの単一の演算で、ハードウェア、ネットワークテクノロジー、およびテンソルのサイズに応じて TensorFlow ランタイムに all-reduce アルゴリズムを自動的に選択することができます。\n",
        "\n",
        "また、追加のパフォーマンス最適化も実装します。たとえば、小さなテンソルの複数の all-reduce をより大きなテンソルのより少ない all-reduce に変換する静的最適化が含まれます。また、プラグインアーキテクチャの設計を進めているため、将来的にはハードウェアにより最適なアルゴリズムをプラグインできるようになる予定です。collective 演算は、broadcast や all-gather などの他の集合演算も実装することに注意してください。\n",
        "\n",
        "次に、`MultiWorkerMirroredStrategy` を作成する最も簡単な方法を示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "m3a_6ebbEjre"
      },
      "outputs": [],
      "source": [
        "multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bt94JBvhEr4s"
      },
      "source": [
        "`MultiWorkerMirroredStrategy` では、現在、2 つの collective 演算の実装を選択することができます。 `CollectiveCommunication.RING` は、gRPC を使用してリング型の collective を通信レイヤーとして実装します。 `CollectiveCommunication.NCCL` は、[Nvidia の NCCL](https://developer.nvidia.com/nccl) を使用して集合を実装します。`CollectiveCommunication.AUTO` は、選択をランタイムに任せます。collective 実装の最適な選択は、GPU の数と種類、およびクラスタ内のネットワーク相互接続によって決まります。これらは、次のようにして指定することができます。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QGX_QAEtFQSv"
      },
      "outputs": [],
      "source": [
        "multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy(\n",
        "    tf.distribute.experimental.CollectiveCommunication.NCCL)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0JiImlw3F77E"
      },
      "source": [
        "マルチワーカートレーニングを進める上でマルチ GPU トレーニングとの主な違いの 1 つに、マルチワーカーのセットアップが挙げられます。`TF_CONFIG` 環境変数は、TensorFlow においてクラスタ構成をそのクラスタの一部である各ワーカーに指定する標準的な方法です。[TF_CONFIG の設定](#TF_CONFIG)についてさらにお読みください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E20tG21LFfv1"
      },
      "source": [
        "注意: このストラテジーは現在改善中であり、より多くのシナリオで機能できるようにしていることから、「[`実験的`](https://www.tensorflow.org/guide/versions#what_is_not_covered)」に指定されています。この改善プロセスの一環として、API の振る舞いが今後変更される可能性があることにご注意ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "45H0Wa8WKI8z"
      },
      "source": [
        "### CentralStorageStrategy\n",
        "\n",
        "`tf.distribute.experimental.CentralStorageStrategy` も同期トレーニングを行います。変数はミラーリングされず、代わりに CPU に配置され、演算はすべてのローカル GPU に複製されます。GPU が 1 つしかない場合は、すべての変数と演算はその GPU に配置されます。\n",
        "\n",
        "次のようにして、`CentralStorageStrategy` のインスタンスを作成します。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rtjZOyaoMWrP"
      },
      "outputs": [],
      "source": [
        "central_storage_strategy = tf.distribute.experimental.CentralStorageStrategy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KY1nJHNkMl7b"
      },
      "source": [
        "これにより、すべての GPU と CPU を使用する `CentralStorageStrategy` インスタンスが作成されます。レプリカでの変数の更新は、変数に適用される前に集計されます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aAFycYUiNCUb"
      },
      "source": [
        "注意: このストラテジーは現在改善中であり、より多くのシナリオで機能できるようにしていることから、「[`実験的`](https://www.tensorflow.org/guide/versions#what_is_not_covered)」に指定されています。この改善プロセスの一環として、API の振る舞いが今後変更される可能性があることにご注意ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3ZLBhaP9NUNr"
      },
      "source": [
        "### ParameterServerStrategy\n",
        "\n",
        "`tf.distribute.experimental.ParameterServerStrategy` は、複数のマシンでのパラメーターサーバートレーニングをサポートします。このセットアップでは、マシンはワーカーとパラメーターサーバーのいずれかに指定されます。モデルの各変数は、1 つのパラメーターサーバーに配置されます。計算は、すべてのワーカーの全 GPU で複製されます。\n",
        "\n",
        "コードは、ほかのストラテジーに似通っています。\n",
        "\n",
        "```\n",
        "ps_strategy = tf.distribute.experimental.ParameterServerStrategy()\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zr1wPHYvOH0N"
      },
      "source": [
        "マルチワーカートレーニングの場合、`TF_CONFIG` はクラスタ内のパラメーターサーバーとワーカーの構成を指定する必要があります。これについては、後に記載の [TF_CONFIG](#TF_CONFIG) を参照してください。\n",
        "\n",
        "注意: このストラテジーは Estimator API とのみ機能します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "t2XUdmIxKljq"
      },
      "source": [
        "### その他のストラテジー\n",
        "\n",
        "上述のストラテジーのほかに、`tf.distribute` API を使用する際のプロトタイピングとデバッグに役立つ可能性のあるストラテジーが 2 つあります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UD5I1beTpc7a"
      },
      "source": [
        "#### デフォルトストラテジー\n",
        "\n",
        "明示的な分散ストラテジーがスコープにない場合には、分散ストラテジーとしてデフォルトのストラテジーが使用されます。`tf.distribute.Strategy` インターフェースを実装しますが、パススルーであるため、実際の分散を提供しません。たとえば、`strategy.run(fn)` は `fn` だけを呼び出します。このストラテジーを使用して書かれたコードは、ストラテジーを指定せずに書かれたコードとまった同じ振る舞いとなります。「演算なし」ストラテジーとして考えるとわかりやすいかもしれません。\n",
        "\n",
        "デフォルトストラテジーはシングルトンであり、インスタンスを 1 つしか作成できません。明示的なストラテジーのスコープの外で、`tf.distribute.get_strategy()` を使って取得することができます（明示的なストラテジーのスコープ内で現在のストラテジーを取得するために使用するのと同じ API）。 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ibHleFOOmPn9"
      },
      "outputs": [],
      "source": [
        "default_strategy = tf.distribute.get_strategy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EkxPl_5ImLzc"
      },
      "source": [
        "このストラテジーには、主に 2 つの目的があります。\n",
        "\n",
        "- 無条件で分散対応のライブラリコードを記述すること。たとえば、オプティマイザーにおいて、`tf.distribute.get_strategy()` を実行し、勾配を減らすためにそのストラテジーを使用します。常に、reduce API を呼び出せるストラテジーオブジェクトを返します。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WECeRzUdT6bU"
      },
      "outputs": [],
      "source": [
        "# In optimizer or other library code\n",
        "# Get currently active strategy\n",
        "strategy = tf.distribute.get_strategy()\n",
        "strategy.reduce(\"SUM\", 1.)  # reduce some values"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JURbH-pUT51B"
      },
      "source": [
        "- ライブラリコードと同様に、条件論理を必要とせずに、分散ストラテジーの有無に関係なく機能するエンドユーザーのプログラムを記述すること。これを説明したサンプルコードスニペットを、次に示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "O4Vmae5jmSE6"
      },
      "outputs": [],
      "source": [
        "if tf.config.list_physical_devices('gpu'):\n",
        "  strategy = tf.distribute.MirroredStrategy()\n",
        "else:  # use default strategy\n",
        "  strategy = tf.distribute.get_strategy() \n",
        "\n",
        "with strategy.scope():\n",
        "  # do something interesting\n",
        "  print(tf.Variable(1.))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kTzsqN4lmJ0d"
      },
      "source": [
        "#### OneDeviceStrategy\n",
        "\n",
        "`tf.distribute.OneDeviceStrategy` は、すべての変数と計算を単一の指定デバイスに配置するストラテジーです。\n",
        "\n",
        "```\n",
        "strategy = tf.distribute.OneDeviceStrategy(device=\"/gpu:0\")\n",
        "```\n",
        "\n",
        "このストラテジーは、多数の点において、デフォルトストラテジーと異なります。デフォルトストラテジーでは、分散ストラテジーを使用せずに TensorFlow を実行した場合と比べ、変数の配置ロジックに変化はありません。しかし、`OneDeviceStrategy` を使用した場合、そのスコープで作成されるすべての変数は、指定されたデバイスに明示的に配置されます。さらに、`OneDeviceStrategy.run` から呼び出される関数も、その指定デバイスに配置されるようになります。\n",
        "\n",
        "このストラテジーを通じて分散された入力は、指定デバイスにプリフェッチされます。デフォルトストラテジーには、入力の分散はありません。\n",
        "\n",
        "デフォルトストラテジーと同様に、このストラテジーも、複数のデバイス/マシンに実際に分散する別のストラテジーに切り替える前のコードテストに使用することができます。これにより、分散ストラテジーの仕組みはある程度はデフォルトストラテジーよりもが強化されますが、`MirroredStrategy` や `TPUStrategy` などを使用した場合ほど最大限には強化されません。ストラテジーが指定されていないかのようなコードの振る舞いを希望する場合は、デフォルトストラテジーを使用してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hQv1lm9UPDFy"
      },
      "source": [
        "これまで、利用できるさまざまなストラテジーとそれらをインスタンス化する方法について説明してきました。次のいくつかのセクションでは、トレーニングを分散する上でストラテジーを使用するためのさまざまな方法について説明します。このガイドでは短いコードスニペットを示し、エンドツーエンドで実行できるチュートリアル全文にリンクしています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_mcuy3UhPcen"
      },
      "source": [
        "## `tf.keras.Model.fit` を使った `tf.distribute.Strategy` の使用\n",
        "\n",
        "TensorFlow の [Keras API 仕様](https://keras.io)の実装である `tf.keras` に `tf.distribute.Strategy` を統合しました。`tf.keras` は、モデルを構築してトレーニングするための高位 API です。`tf.keras` バックエンドに統合することによって、`model.fit` を使用する Keras トレーニングフレームワークに記述されたトレーニングの分散をシームレスに行えるようになっています。\n",
        "\n",
        "コードを次のように変更してください。\n",
        "\n",
        "1. 適切な `tf.distribute.Strategy` のインスタンスを作成します。\n",
        "2. Keras モデル、オプティマイザー、およびメトリックの作成を `strategy.scope` 内に移動します。\n",
        "\n",
        "Sequential、Functional、および Subclassed のすべての Keras モデルをサポートしています。\n",
        "\n",
        "次に、1 つの高密度レイヤーを持つ非常に単純な Keras モデルに対してこれを実行するコードスニペットを示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gbbcpzRnPZ6V"
      },
      "outputs": [],
      "source": [
        "mirrored_strategy = tf.distribute.MirroredStrategy()\n",
        "\n",
        "with mirrored_strategy.scope():\n",
        "  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])\n",
        "\n",
        "model.compile(loss='mse', optimizer='sgd')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "773EOxCRVlTg"
      },
      "source": [
        "この例では、複数の GPU を持つマシンで実行できるように、`MirroredStrategy` を使用しています。`strategy.scope()` は、トレーニングの分散に度のストラテジーを使用するかを Keras に示しています。このスコープ内にモデル/オプティマイザー/メトリックを作成することで、通常の変数ではなく、分散化された変数を作成することができます。これをセットアップしたら、通常通り、モデルをフィットさせることができます。利用できる GPU に対するモデルのトレーニングの複製や勾配の集計などは、`MirroredStrategy` によって行われます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZMmxEFRTEjH5"
      },
      "outputs": [],
      "source": [
        "dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(10)\n",
        "model.fit(dataset, epochs=2)\n",
        "model.evaluate(dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nofTLwyXWHK8"
      },
      "source": [
        "ここでは、`tf.data.Dataset` を使用してトレーニングと eval 入力を提供していますが、次のように numpy 配列を使用することもできます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Lqgd9SdxW5OW"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "inputs, targets = np.ones((100, 1)), np.ones((100, 1))\n",
        "model.fit(inputs, targets, epochs=2, batch_size=10)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IKqaj7QwX0Zb"
      },
      "source": [
        "いずれの場合（dataset または numpy）でも、指定された入力の各バッチは、複数のレプリカで均等に分割されます。たとえば、2 GPU で `MirroredStrategy` を使用している場合、サイズが 10 の各バッチは 2 GPU 間で分割されるため、各ステップでそれぞれに 5 つの入力例が提供されます。その後、GPU をさらに追加するにつれ、各エポックはより高速にトレーニングするようになります。一般的に、アクセラレータを増やすたびにバッチサイズを増加することが望ましく、そうすることで、追加の計算パワーを有効活用できるようになります。また、モデルに応じて学習速度を再調整することも必要です。レプリカの数を取得するには、`strategy.num_replicas_in_sync` を使用できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "quNNTytWdGBf"
      },
      "outputs": [],
      "source": [
        "# Compute global batch size using number of replicas.\n",
        "BATCH_SIZE_PER_REPLICA = 5\n",
        "global_batch_size = (BATCH_SIZE_PER_REPLICA *\n",
        "                     mirrored_strategy.num_replicas_in_sync)\n",
        "dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100)\n",
        "dataset = dataset.batch(global_batch_size)\n",
        "\n",
        "LEARNING_RATES_BY_BATCH_SIZE = {5: 0.1, 10: 0.15}\n",
        "learning_rate = LEARNING_RATES_BY_BATCH_SIZE[global_batch_size]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z1Muy0gDZwO5"
      },
      "source": [
        "### 現在、何がサポートされていますか？\n",
        "\n",
        "トレーニング API | MirroredStrategy | TPUStrategy | MultiWorkerMirroredStrategy | CentralStorageStrategy | ParameterServerStrategy\n",
        "--- | --- | --- | --- | --- | ---\n",
        "Keras API | サポート中 | サポート中 | 実験的サポート | 実験的サポート | 2.3 以降でサポート予定\n",
        "\n",
        "### 例とチュートリアル\n",
        "\n",
        "次は、上述した Keras のエンドツーエンド統合を説明するチュートリアルと例の一覧です。\n",
        "\n",
        "1. <code>MirroredStrategy</code> で MNIST をトレーニングする<a>チュートリアル</a>\n",
        "2. `MultiWorkerMirroredStrategy` を使って MNIST をトレーニングする[チュートリアル](https://www.tensorflow.org/tutorials/distribute/multi_worker_with_keras)\n",
        "3. `TPUStrategy` による MNIST のトレーニングに関する[ガイド](https://www.tensorflow.org/guide/tpu#train_a_model_using_keras_high_level_apis)\n",
        "4. さまざまなストラテジーを使って実装された最新モデルのコレクションが含まれる TensorFlow Model Garden [リポジトリ](https://github.com/tensorflow/models/tree/master/official)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IlYVC0goepdk"
      },
      "source": [
        "## カスタムトレーニングループを使った `tf.distribute.Strategy` の使用\n",
        "\n",
        "これまで見てきたように、Keras の `model.fit` で `tf.distribute.Strategy` を使用するにはコードの数行のみを変更する必要がありました。もう少し手を加えるれば、カスタムトレーニングループでも `tf.distribute.Strategy` を使用できるようになります。\n",
        "\n",
        "トレーニングループに Estimator や Keras よりも高い柔軟性と制御が必要な場合は、カスタムトレーニングループを作成することができます。たとえば、GANを使用する際に、各ラウンドで異なる数のジェネレータやディスクリミネータのステップを実行することができます。同様に、高度なフレームワークは、強化学習トレーニングにはあまり適していません。\n",
        "\n",
        "カスタムとレニングループをサポートするために、`tf.distribute.Strategy` クラスでメソッドのコアセットを提供しています。これらを使用するには、最初にコードをわずかに再構成する必要があるかもしれませんが、それを一度行うと、ストラテジーインスタンスを変更するだけで、GPU、TPU、および複数のマシンを切り替えられるようになります。\n",
        "\n",
        "ここでは、以前と同じ Keras モデルを使って、単純なトレーニングでの使用事例を表した簡単なスニペットを示します。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XNHvSY32nVBi"
      },
      "source": [
        "まず、ストラテジーのスコープ内にモデルとオプティマイザーを作成します。こうすることで、そのモデルとオプティマイザーを使って作成された変数がミラーリングされた変数であることを保証することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "W-3Bn-CaiPKD"
      },
      "outputs": [],
      "source": [
        "with mirrored_strategy.scope():\n",
        "  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])\n",
        "  optimizer = tf.keras.optimizers.SGD()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mYkAyPeYnlXk"
      },
      "source": [
        "次に、入力データセットを作成し、`tf.distribute.Strategy.experimental_distribute_dataset` を呼び出して、ストラテジーに応じてデータセットを分散します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "94BkvkLInkKd"
      },
      "outputs": [],
      "source": [
        "dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(\n",
        "    global_batch_size)\n",
        "dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "grzmTlSvn2j8"
      },
      "source": [
        "そして、トレーニングの一ステップを定義します。勾配とオプティマイザーを計算し、その勾配を適用してモデルの変数を更新するために、`tf.GradientTape` を使用します。このトレーニングステップを分散するには、`train_step` 関数に入れて、前に作成した `dist_dataset` から取得するデータセット入力とともに、`tf.distrbute.Strategy.run` に渡します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NJxL5YrVniDe"
      },
      "outputs": [],
      "source": [
        "loss_object = tf.keras.losses.BinaryCrossentropy(\n",
        "  from_logits=True,\n",
        "  reduction=tf.keras.losses.Reduction.NONE)\n",
        "\n",
        "def compute_loss(labels, predictions):\n",
        "  per_example_loss = loss_object(labels, predictions)\n",
        "  return tf.nn.compute_average_loss(per_example_loss, global_batch_size=global_batch_size)\n",
        "\n",
        "def train_step(inputs):\n",
        "  features, labels = inputs\n",
        "\n",
        "  with tf.GradientTape() as tape:\n",
        "    predictions = model(features, training=True)\n",
        "    loss = compute_loss(labels, predictions)\n",
        "\n",
        "  gradients = tape.gradient(loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
        "  return loss\n",
        "\n",
        "@tf.function\n",
        "def distributed_train_step(dist_inputs):\n",
        "  per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))\n",
        "  return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,\n",
        "                         axis=None)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yRL5u_NLoTvq"
      },
      "source": [
        "上記のコードには、注意すべき点がいくつかあります。\n",
        "\n",
        "1. `tf.nn.compute_average_loss` を使用して損失を計算しました。`tf.nn.compute_average_loss` は例ごとの損失を加算し、その和を global_batch_size で除算します。これは、各レプリカで勾配が計算された後、その勾配を**加算**することで、レプリカ全体の勾配が集計されるため重要です。\n",
        "2. `tf.distribute.Strategy.run` が返す結果を集計するために、`tf.distribute.Strategy.reduce` API を使用しました。`tf.distribute.Strategy.run` は、ストラテジーの各ローカルレプリカの結果を返し、この結果の消費方法もさまざまです。集計された値を取得するには、結果を `reduce` することができます。また、`tf.distribute.Strategy.experimental_local_results` を実行して、結果に含まれる、ローカルレプリカ当たり 1 つの値のリストを取得することもできます。\n",
        "3. 分散ストラテジーのスコープ内で `apply_gradients` が呼び出されると、その振る舞いが変更されます。具体的には、同期トレーニング中に各並列インスタンスに勾配を適用する前に、勾配の sum-over-all-replicas を実行します。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o9k_6-6vpQ-P"
      },
      "source": [
        "最後に、トレーニングステップの定義が済んだら、`dist_dataset` をイテレートしてトレーニングをループで実行できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Egq9eufToRf6"
      },
      "outputs": [],
      "source": [
        "for dist_inputs in dist_dataset:\n",
        "  print(distributed_train_step(dist_inputs))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jK8eQXF_q1Zs"
      },
      "source": [
        "上記の例では、`dist_dataset` をイテレートして、トレーニングに入力を提供しました。また、numpy 入力をサポートするために、`tf.distribute.Strategy.make_experimental_numpy_dataset` も提供しています。`tf.distribute.Strategy.experimental_distribute_dataset` を呼び出す前にこの API を使って、データセットを作成することができます。\n",
        "\n",
        "データをイテレートするための別の方法は、明示的にイテレータを使用することです。データセット全体をイテレートするのに対し、特定のステップ数だけ実行する場合に、これを行うことができます。上記のイテレートは、最初にイテレータを作成し、それに明示的に`next` を呼び出して入力データを取得するように変更されます。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e5BEvR0-LJAc"
      },
      "outputs": [],
      "source": [
        "iterator = iter(dist_dataset)\n",
        "for _ in range(10):\n",
        "  print(distributed_train_step(next(iterator)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vDJO8mnypqBA"
      },
      "source": [
        "これは、` tf.distribute.Strategy ` APIを使用してカスタムトレーニングループを分散する最も単純な事例をカバーしています。これらの API は改善プロセスにあります。この使用事例にはコードを適合させる作業がさらに必要であるため、いずれ、詳細なガイドを別途公開する予定です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BZjNwCt1qBdw"
      },
      "source": [
        "### 現在、何がサポートされていますか？\n",
        "\n",
        "トレーニング API | MirroredStrategy | TPUStrategy | MultiWorkerMirroredStrategy | CentralStorageStrategy | ParameterServerStrategy\n",
        ":-- | :-- | :-- | :-- | :-- | :--\n",
        "カスタムトレーニングループ | サポート中 | サポート中 | 実験的サポート | 実験的サポート | 2.3 以降でサポート予定\n",
        "\n",
        "### 例とチュートリアル\n",
        "\n",
        "次は、カスタムトレーニングループを使って分散ストラテジーを使用するいくつかの例です。\n",
        "\n",
        "1. `MirroredStrategy` で MNIST をトレーニングする[チュートリアル](https://www.tensorflow.org/tutorials/distribute/custom_training)\n",
        "2. `TPUStrategy` による MNIST のトレーニングに関する[ガイド](https://www.tensorflow.org/guide/tpu#train_a_model_using_custom_training_loop)\n",
        "3. さまざまなストラテジーを使って実装された最新モデルのコレクションが含まれる TensorFlow Model Garden [リポジトリ](https://github.com/tensorflow/models/tree/master/official)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nO0hmFCRoIll"
      },
      "source": [
        "## Estimator を使った `tf.distribute.Strategy` の使用（制限サポート）\n",
        "\n",
        "`tf.estimator` は、もともと非同期パラメーターサーバー手法をサポートしていた分散型トレーニング TensorFlow API です。Keras と同様に、`tf.distribute.Strategy` を `tf.Estimator` に統合しています。トレーニングに Estimator を使用している場合、コードを少し変更するだけで、分散型トレーニングに簡単に変更することができます。これにより、Estimator ユーザーは複数の GPU と複数のワーカーだけでなく、TPU でも同期分散型トレーニングを実行できるようになりました。ただし、Estimator でのこのサポートには制限があります。詳細については、以下に示す「[現在、何がサポートされていますか](#estimator_support)」セクションを参照してください。\n",
        "\n",
        "Estimator での `tf.distribute.Strategy` の使用は、Keras の事例とわずかに異なります。`strategy.scope` を使用する代わりに、ストラテジーオブジェクトを Estimator の [`RunConfig`](https://www.tensorflow.org/api_docs/python/tf/estimator/RunConfig) に渡します。\n",
        "\n",
        "次は、事前に作成された Estimator `LinearRegressor` と `MirroredStrategy` を使ってこの動作を示すコードスニペットです。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oGFY5nW_B3YU"
      },
      "outputs": [],
      "source": [
        "mirrored_strategy = tf.distribute.MirroredStrategy()\n",
        "config = tf.estimator.RunConfig(\n",
        "    train_distribute=mirrored_strategy, eval_distribute=mirrored_strategy)\n",
        "regressor = tf.estimator.LinearRegressor(\n",
        "    feature_columns=[tf.feature_column.numeric_column('feats')],\n",
        "    optimizer='SGD',\n",
        "    config=config)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "n6eSfLN5RGY8"
      },
      "source": [
        "ここでは、事前に作成された Estimator が使用されていますが、同じコードはカスタムの Estimator でも動作します。`train_distribute` はトレーニングの分散方法を判定し、`eval_distribute` は評価の分散方法を判定します。この点も、トレーニングと評価に同じストラテジーを使用する Keras と異なるところです。\n",
        "\n",
        "入力関数を使用して、この Estimator をトレーニングし、評価することができます。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2ky2ve2PB3YP"
      },
      "outputs": [],
      "source": [
        "def input_fn():\n",
        "  dataset = tf.data.Dataset.from_tensors(({\"feats\":[1.]}, [1.]))\n",
        "  return dataset.repeat(1000).batch(10)\n",
        "regressor.train(input_fn=input_fn, steps=10)\n",
        "regressor.evaluate(input_fn=input_fn, steps=10)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hgaU9xQSSk2x"
      },
      "source": [
        "Estimator と Keras のもう 1 つの違いとして強調すべき点は<br>入力の処理方法です。Keras では、データセットの各バッチは複数のレプリカに自動的に分断されると説明しました。一方、Estimator の場合は、バッチの自動分断やワーカーをまたいで自動的にシャーディングすることもありません。ワーカーやデバイスでのデータの分散方法はユーザーが完全に制御するものであるため、`input_fn` を提供してデータの分散方法を指定する必要があります。\n",
        "\n",
        "`input_fn` はワーカー当たり一度呼び出されるため、ワーカー当たり 1 つのデータセットが与えられます。次に、そのデータセットの 1 つのバッチがそのワーカーの 1 つのレプリカに供給され、したがって、1 つのワーカーの N 個のレプリカに対して N 個のバッチが消費されることになります。言い換えると、`input_fn` が返すデータセットは、サイズ `PER_REPLICA_BATCH_SIZE` のバッチを提供するということです。ステップのグローバルバッチサイズは、`PER_REPLICA_BATCH_SIZE * strategy.num_replicas_in_sync` として取得することができます。\n",
        "\n",
        "マルチワーカートレーニングを行う場合は、データをワーカー間で分割するか、それぞれにランダムシードを使用してシャッフルする必要があります。これを行う方法の例は、「[Multi-worker Training with Estimator](../tutorials/distribute/multi_worker_with_estimator.ipynb)（Estimator を使ったマルチワーカートレーニング）」を参照してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G3ieQKfWZhhL"
      },
      "source": [
        "また、同様に、マルチワーカーとパラメーターサーバーストラテジーを使用することができます。コードは変わりませんが、`tf.estimator.train_and_evaluate` を使用し、クラスタで実行している各バイナリの `TF_CONFIG` 環境変数を設定する必要があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A_lvUsSLZzVg"
      },
      "source": [
        "<a name=\"estimator_support\"></a>\n",
        "\n",
        "### 現在、何がサポートされていますか？\n",
        "\n",
        "`TPUStrategy` を除くすべてのストラテジーを使った Estimator でのトレーニングのサポートには制限があります。基本的なトレーニングと評価は機能しますが、scaffold などの多数の高度な機能はまだ機能しません。この統合には多数のバグも存在する可能性があります。現時点では、このサポートを積極的に改善する予定はなく、代わりに Keras とカスタムトレーニングループのサポートに注力する意向です。可能な限り、それらの API で `tf.distribute` をご利用ください。\n",
        "\n",
        "トレーニング API | MirroredStrategy | TPUStrategy | MultiWorkerMirroredStrategy | CentralStorageStrategy | ParameterServerStrategy\n",
        ":-- | :-- | :-- | :-- | :-- | :--\n",
        "Estimator API | 制限サポート | 未サポート | 制限サポート | 制限サポート | 制限サポート\n",
        "\n",
        "### 例とチュートリアル\n",
        "\n",
        "次は、Estimatorを使用したさまざまなストラテジーのエンドツーエンドの使用法を示すいくつかの例です。\n",
        "\n",
        "1. `MultiWorkerMirroredStrategy` でマルチワーカーを持つ MNIST をトレーニングする、[Multi-worker Training with Estimator](../tutorials/distribute/multi_worker_with_estimator.ipynb)\n",
        "2. Kubernotes テンプレートを使った tensorflow/ecosystem でマルチワーカートレーニングを行うための[エンドツーエンドの例](https://github.com/tensorflow/ecosystem/tree/master/distribution_strategy)。この例は最初に Keras モデルを使用し、それを `tf.keras.estimator.model_to_estimator` API を使って Estimator に変換します。\n",
        "3. [ResNet50](https://github.com/tensorflow/models/blob/master/official/vision/image_classification/resnet_imagenet_main.py) 公式モデル。`MirroredStrategy` または `MultiWorkerMirroredStrategy` を使ってトレーニングできます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xk0JdsTHyUnE"
      },
      "source": [
        "## その他のトピック\n",
        "\n",
        "このセクションでは、複数の使用事例に関連のあるトピックをいくつかカバーしています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cP6BUIBtudRk"
      },
      "source": [
        "<a name=\"TF_CONFIG\"></a>\n",
        "\n",
        "### TF_CONFIG 環境変数のセットアップ\n",
        "\n",
        "マルチワーカートレーニングでは、前述のとおり、クラスタで実行されている各バイナリに対して ` TF_CONFIG` 環境変数を設定する必要があります。`TF_CONFIG` 環境変数は、クラスタを構成するタスク、そのアドレス、およびクラスタ内の各タスクのロールを指定する JSON 文字列です。[tensorflow/ecosystem](https://github.com/tensorflow/ecosystem) レポジトリには、トレーニングタスクの `TF_CONFIG` を設定する Kubernotes テンプレートを提供しています。\n",
        "\n",
        "TF_CONFIG には、cluster と task の 2 つのコンポーネントがあります。 cluster は、トレーニングクラスタに関する情報を提供します。これは、ワーカーなどのさまざまなタイプのジョブで構成される辞書です。マルチワーカートレーニングでは、通常、一般的なワーカーの作業に加えて、チェックポイントの保存や TensorBoard のサマリーファイルの書き込みなど、ほかよりタスクを担うワーカーが 1 つあります。こういったワーカーは、「チーフ」ワーカーと呼ばれ、インデックス 0 のワーカーがチーフワーカーに指定されるようになっています（事実、これが、tf.distribute.Strategy が実装された理由です）。一方の task は現在のタスクの情報を提供します。最初のコンポーネント cluster はすべてのワーカーで同じものですが、2 つ目のコンポーネント task は各ワーカーによって異なり、そのワーカーの種類とインデックスを指定します。\n",
        "\n",
        "次は、`TF_CONFIG` の一例です。\n",
        "\n",
        "```\n",
        "os.environ[\"TF_CONFIG\"] = json.dumps({     \"cluster\": {         \"worker\": [\"host1:port\", \"host2:port\", \"host3:port\"],         \"ps\": [\"host4:port\", \"host5:port\"]     },    \"task\": {\"type\": \"worker\", \"index\": 1} })\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fezd3aF8wj9r"
      },
      "source": [
        "この ` TF_CONFIG `は、クラスタ内に 3 つのワーカーと 2 つの ps タスク、およびそれらのホストとポートがあることを指定しています。 「task」の部分は、クラスタ worker 1（2番目のワーカー）内の現在のタスクのロールを指定します。 クラスタ内の有効なロールは、「chi-ef」、「worker」、「ps」、および「evaluator」です。`tf.distribute.experimental.ParameterServerStrategy `を使用する場合を除いて、「ps」ジョブはありません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GXIbqSW-sFVg"
      },
      "source": [
        "## 次のステップ\n",
        "\n",
        "`tf.distribute.Strategy` は積極的な開発が進められています。ぜひお試しいただき、[GitHub 課題](https://github.com/tensorflow/tensorflow/issues/new) に皆さんの感想をお寄せください。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "Tce3stUlHN0L"
      ],
      "name": "distributed_training.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
